// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "NeuronDataReader/DataType.h"
#include "Interfaces/IPv4/IPv4Endpoint.h"

////////////////////////////
/// Ability interfaces
////////////////////////////

class INeuronDataReceiveAbility;

class INeuronInitAbility
{
public:
	virtual void Init( ) = 0;
	virtual void Uninit( ) = 0;
	virtual ~INeuronInitAbility( ) = default;
};

class INeuronFrameCallback
{
public:
	virtual void OnFrame( BvhDataHeader* Header, float* Data ) = 0;
	virtual ~INeuronFrameCallback( ) = default;
};

class INeuronDataDispatchAbility
{
public:
	DECLARE_EVENT_TwoParams( INeuronDataDispatchAbility, FOnNeuronFrame, BvhDataHeader*, float* );
	typedef FOnNeuronFrame::FDelegate FNeuronFrameDelegate;
	virtual FOnNeuronFrame& OnNeuronFrameArrived( ) = 0;
	virtual void Dispatch( BvhDataHeader* Header, float* Data ) = 0;
	virtual ~INeuronDataDispatchAbility( ) {}
};

using FNeuronFrameDelegate = INeuronDataDispatchAbility::FNeuronFrameDelegate;

class INeuronNetConfigBaseAbility
{
public:
	virtual bool Equals( TSharedPtr<INeuronNetConfigBaseAbility> Other ) = 0;
	virtual bool IsTcpConfig( ) const = 0;
	virtual ~INeuronNetConfigBaseAbility( ) {}
};

class INeuronTcpConfigAbility : public INeuronNetConfigBaseAbility
{
public:
	virtual void SetRemoteEndpoint( FIPv4Endpoint Endpoint ) = 0;
	virtual bool SetRemoteEndpointFromString( const FString& EndpointStr ) = 0;
	virtual FIPv4Endpoint GetRemoteEndpoint( ) = 0;

	virtual ~INeuronTcpConfigAbility( ) {}
};

class INeuronUdpConfigAbility : public INeuronNetConfigBaseAbility
{
public:
	virtual void SetLocalPort( uint16 Port ) = 0;
	virtual uint16 GetPort( ) = 0;

	virtual ~INeuronUdpConfigAbility( ) {}
};

using ConnectionStatus = SocketStatus;

class INeuronConnectionAbility
{
public:
	virtual void SetConfig( TSharedPtr<INeuronNetConfigBaseAbility> Config ) = 0;
	virtual TSharedPtr<INeuronNetConfigBaseAbility> GetConfig( ) = 0;

	virtual ConnectionStatus GetStatus( ) = 0;
	virtual SOCKET_REF& GetConnectionSocket( ) = 0;

	virtual bool Setup( ) = 0;
	virtual void Cutoff( ) = 0;

	virtual ~INeuronConnectionAbility( ) {}
};

class INeuronDataSourceAbility : public INeuronDataDispatchAbility, public INeuronConnectionAbility
{
public:
	virtual ~INeuronDataSourceAbility( ) {}
};

class INeuronDataReceiveAbility : public INeuronInitAbility
{
public:
	virtual FDelegateHandle AttachReceiveFunctionToDispatcher( TSharedPtr<INeuronDataDispatchAbility> NeuronDispatcher, INeuronDataDispatchAbility::FNeuronFrameDelegate Delegate ) = 0;
	virtual void DetachReceiveFunctionFromDispatcher( TSharedPtr<INeuronDataDispatchAbility> NeuronDispatcher, FDelegateHandle RecvFnHandle ) = 0;

public:
	virtual ~INeuronDataReceiveAbility( ) {}
};


////////////////////////////////////////
/// NeuronDataReader Callback Bridge
////////////////////////////////////////
class INeuronCallbackBridge
{
public:
	virtual void RegisterDataSource( TSharedPtr<INeuronDataSourceAbility> DataSource ) = 0;
	virtual void UnRegisterDataSource( TWeakPtr<INeuronDataSourceAbility> DataSource ) = 0;
	virtual void UnRegisterDataSourceRef( TSharedPtr<INeuronDataSourceAbility>& DataSourceRef ) = 0;
	virtual TSharedPtr<INeuronDataSourceAbility> QueryDataSource( TSharedPtr<INeuronNetConfigBaseAbility> Config ) = 0;
	virtual ~INeuronCallbackBridge( ) {}

	static NEURONDATAREADERPLUGIN_API INeuronCallbackBridge& Get( );
};
